package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.entity.CartInfo;
import com.atguigu.gmall.cart.entity.UserAuth;
import com.atguigu.gmall.cart.repository.CartRepository;
import com.atguigu.gmall.cart.service.CartService;
import com.atguigu.gmall.cart.vo.SuccessCartVo;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.execption.GmallException;
import com.atguigu.gmall.common.interceptor.component.UserAuthComponent;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.JSONs;
import com.atguigu.gmall.common.util.MathUtil;
import com.atguigu.gmall.feign.product.SkuDetailItemFeignClient;
import com.atguigu.gmall.product.entity.SkuInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.Duration;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author:lyd
 * @Date:2023/9/1 19:35
 * @Version:1.0
 * @Description
 **/
@Service
@Slf4j
public class CartServiceImpl implements CartService {
    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    CartRepository cartRepository;

    @Autowired
    SkuDetailItemFeignClient skuDetailItemFeignClient;

    @Autowired
    UserAuthComponent userAuthComponent;
    /**
     * 判断购物车用哪个键
     *
     * @return
     */
    @Override
    public String determineKey() {
        UserAuth userAuth = userAuthComponent.getUserAuth();
        //cart:info:
        //判断购物车使用哪个键
        String cartKey = RedisConst.CART_INFO + (userAuth.getUserId() != null ? userAuth.getUserId() : userAuth.getUserTempId());
        return cartKey;
    }

    /**
     * 获取UserAuth的数据,判断cookie或者header中是否有值
     *
     * @return
     */


    /**
     * 向购物车中添加商品
     *
     * @param skuId
     * @param skuNum
     * @param cartKey
     * @return
     */
    @Override
    public SuccessCartVo addCart(Long skuId, Integer skuNum, String cartKey) {

        //添加商品分2步：
        //------------> 1、判断redis中是否有商品，有的话则直接更改数字
        //------------> 2、redis中没有商品，直接往里面加
        SuccessCartVo cartVo = new SuccessCartVo();

        HashOperations<String, String, String> hash = redisTemplate.opsForHash();
        Boolean IsSkuInfo = hash.hasKey(cartKey, skuId.toString());
        //redis中有商品
        if (IsSkuInfo) {
            //获取redis已经保存的CartInfo
            CartInfo cartInfo = cartRepository.getCartInfo(cartKey, skuId);
            //更新数量
            cartInfo.setSkuNum(cartInfo.getSkuNum() + skuNum);
            //保存更新后的数据
            cartRepository.saveCartInfo(cartKey, cartInfo);
            //给页面返回封装的数据SuccessCartVo
            SkuInfo skuInfo = cartInfoToSkuInfo(cartInfo);
            cartVo.setSkuInfo(skuInfo);
            cartVo.setSkuNum(cartInfo.getSkuNum());

        } else {
            //redis没有商品

            //给购物车中增加商品时，如果超出了购物车的最大限度则不能添加
            Long cartSize = cartRepository.getCartSize(cartKey);
            if (cartSize + 1 > RedisConst.CART_ITEM_MAXNUM) {
                throw new GmallException(ResultCodeEnum.CART_ITEM_MAXNUM);
            }
            //获取SkuInfo
            Result<SkuInfo> skuinfo = skuDetailItemFeignClient.getSkuinfo(skuId);
            //转换
            CartInfo cartInfo = skuInfoToCartInfo(skuinfo.getData());
            cartInfo.setSkuNum(skuNum);
            //保存
            cartRepository.saveCartInfo(cartKey, cartInfo);

            //给页面返回封装的数据SuccessCartVo
            cartVo.setSkuInfo(skuinfo.getData());
            cartVo.setSkuNum(skuNum);
        }
        //给临时购物车设置过期时间
        UserAuth userAuth = userAuthComponent.getUserAuth();
        if ((userAuth.getUserId() == null)) {
            //判断是否已经设置过期时间
            Long expire = redisTemplate.getExpire(cartKey);
            if (expire < 0) {
                //没有设置过期时间，此时默认的过期时间是-1
                cartRepository.setTempCartTtl(cartKey, Duration.ofDays(365));
            }
        }

        return cartVo;
    }

    /**
     * 查询购物车中的所有商品
     *
     * @param cartKey
     * @return
     */
    @Override
    public List<CartInfo> list(String cartKey) {
        UserAuth userAuth = userAuthComponent.getUserAuth();
        if (userAuth.getUserId() != null) {
            //说明此时用户已经登录
            List<CartInfo> tempCart = cartRepository.list(RedisConst.CART_INFO + userAuth.getUserTempId());
            if (tempCart != null) {
                //说明用户登录前在购物车中添加了商品。此时，触发合并购物车
                for (CartInfo cartInfo : tempCart) {
                    try {
                        //向购物车中添加商品
                        addCart(cartInfo.getSkuId(), cartInfo.getSkuNum(), RedisConst.CART_INFO + userAuth.getUserId());
                        //删除添加完的商品
                        cartRepository.deleteItem(RedisConst.CART_INFO + userAuth.getUserTempId(), cartInfo.getSkuId());
                    } catch (GmallException e) {
                        //临时购物车中的数据超限
                        throw new GmallException(ResultCodeEnum.CART_TEMP_TOO_MUCH);
                    }
                }
            }
        }
        //这里会动态获取，用户购物车或者临时购物车
        List<CartInfo> cartInfoList = cartRepository.list(cartKey);

        //为了保证购物车中的商品价格和商品实时变化的价格一致，我们在用户点击购物车时触发更新价格操作
        cartInfoList.stream()
                .parallel()//并行流，自动等待，可以让foreach循环中语句并行执行
                .forEach(item -> {
                    BigDecimal skuPrice = item.getSkuPrice();
                    //商品的实时价格
                    Result<BigDecimal> price = skuDetailItemFeignClient.getPrice(item.getSkuId());
                    if (!MathUtil.decimalEquals(skuPrice, price.getData())) {
                        //商品价格变化
                        log.info("购物车：{} 商品：{} 价格由：{}，变为：{}，正在同步价格", cartKey, item.getSkuId(),skuPrice, price);
                        item.setSkuPrice(price.getData());
                        cartRepository.saveCartInfo(cartKey, item);
                    }
                });

        return cartInfoList;

    }

    /**
     * 更改商品选中状态
     *
     * @param skuId
     * @param checked
     * @param cartKey
     */
    @Override
    public void checkCart(Long skuId, Integer checked, String cartKey) {
        CartInfo cartInfo = cartRepository.getCartInfo(cartKey, skuId);
        cartInfo.setIsChecked(checked);
        cartRepository.saveCartInfo(cartKey, cartInfo);
    }

    @Override
    public void deleteCart(Long skuId, String cartKey) {
        redisTemplate.opsForHash().delete(cartKey, skuId.toString());
    }

    /**
     * 增加或减少购物车中商品的数量
     *
     * @param skuId
     * @param num
     * @param cartKey
     */
    @Override
    public void addToCart(Long skuId, Integer num, String cartKey) {
        CartInfo cartInfo = cartRepository.getCartInfo(cartKey, skuId);
        cartInfo.setSkuNum(cartInfo.getSkuNum() + num);
        cartRepository.saveCartInfo(cartKey, cartInfo);
    }

    /**
     * 删除批量选中的商品
     *
     * @param cartKey
     */
    @Override
    public void deleteChecked(String cartKey) {
        List<Long> idList = cartRepository.getSkuIdList(cartKey);
        if (idList == null) {
            throw new GmallException(ResultCodeEnum.CART_EMPTY);
        }
        Object[] objects = idList.stream()
                .map(item -> item.toString())
                .toArray();
        //批量删除redis中选中的商品数据
        redisTemplate.opsForHash().delete(cartKey, objects);

    }

    /**
     * 获取购物车中选中的数据
     * @param key
     * @return
     */
    @Override
    public List<CartInfo> getChecked(String key) {
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(key)
                .stream()
                .map(json -> JSONs.jsonToObj((String) json, CartInfo.class))
                .filter(item -> item.getIsChecked() == 1)
                .collect(Collectors.toList());
        return cartInfoList;

    }

    /**
     * 将传入的SkuInfo转换为CartInfo
     *
     * @param skuinfo
     * @return
     */
    private CartInfo skuInfoToCartInfo(SkuInfo skuinfo) {
        CartInfo cartInfo = new CartInfo();
        cartInfo.setSkuId(skuinfo.getId());
        //保存商品第一次加入购物车时的价格
        cartInfo.setCartPrice(skuinfo.getPrice());
        //保存商品的实时展示价格
        cartInfo.setSkuPrice(skuinfo.getPrice());
        cartInfo.setImgUrl(skuinfo.getSkuDefaultImg());
        cartInfo.setSkuName(skuinfo.getSkuName());
        cartInfo.setIsChecked(1);
        cartInfo.setCreateTime(new Date());
        cartInfo.setUpdateTime(new Date());

        return cartInfo;
    }


    /**
     * 通过CartInfo获取SkuInfo的部分信息
     *
     * @param cartInfo
     * @return
     */
    private static SkuInfo cartInfoToSkuInfo(CartInfo cartInfo) {
        SkuInfo skuInfo = new SkuInfo();
        skuInfo.setId(cartInfo.getId());
        skuInfo.setPrice(cartInfo.getCartPrice());
        skuInfo.setSkuDefaultImg(cartInfo.getImgUrl());
        skuInfo.setSkuName(cartInfo.getSkuName());
        return skuInfo;
    }
}
